package com.jxm.a05;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Set;

/*
    BeanFactory 后处理器的作用
 */
public class A05 {
    private static final Logger log = LoggerFactory.getLogger(A05.class);

    public static void main(String[] args) throws IOException {

        // ⬇️GenericApplicationContext 是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
//        context.registerBean(ConfigurationClassPostProcessor.class); // @ComponentScan @Bean @Import @ImportResource
//        context.registerBean(MapperScannerConfigurer.class, bd -> { // @MapperScanner
//            bd.getPropertyValues().add("basePackage", "com.jxm.a05.mapper");
//        });

//        context.registerBean(ComponentScanPostProcessor.class); // 解析 @ComponentScan
        context.registerBean(AtBeanPostProcessor.class); // 解析 @Bean
        context.registerBean(MapperPostProcessor.class); //解析Mapper接口

        /**
         * 解析 @ComponentScan BeanFactory后置处理器
         */
//        ComponentScan annotation = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
//        if (annotation != null) {
//            for (String p : annotation.basePackages()) {
////                System.out.println(p);
//                //com.jxm.a05.component ->classpath:*com/jxm/a05/component/**/*.class
//                String path = "classpath*:" + p.replace(".","/") + "/**/*.class";
//                System.out.println(path);
//                CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
//                Resource[] resources = context.getResources(path);
//                AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
//                for (Resource resource : resources) {
//                    MetadataReader reader = readerFactory.getMetadataReader(resource);
//                    System.out.println("类名："+reader.getClassMetadata().getClassName());
//                    AnnotationMetadata metadata = reader.getAnnotationMetadata();
//                    System.out.println("是否加了Component注解："+metadata.hasAnnotation(Component.class.getName()));
//                    System.out.println("是否加了Component派生："+metadata.hasMetaAnnotation(Component.class.getName()));
//                    if (metadata.hasAnnotation(Component.class.getName()) ||
//                            metadata.hasMetaAnnotation(Component.class.getName())){
//                        //获取bean定义
//                        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata()
//                                .getClassName()).getBeanDefinition();
//                        //获取bean名字
//                        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
//                        String name = generator.generateBeanName(beanDefinition, beanFactory);
//                        //注册bean定义到工厂
//                        beanFactory.registerBeanDefinition(name,beanDefinition);
//                    }
//                }
//            }
//        }

        /**
         * 解析 @Bean BeanFactory后置处理器
         */
//        CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
//        //读取Config类信息
//        MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/jxm/a05/Config.class"));
//        //获取被@Bean标注的方法元数据
//        Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
//        for (MethodMetadata method : methods) {
////            System.out.println(method);
//            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
//            builder.setFactoryMethodOnBean(method.getMethodName(), "config");
//            AbstractBeanDefinition bd = builder.getBeanDefinition();
//            context.getDefaultListableBeanFactory().registerBeanDefinition(method.getMethodName(), bd);
//            //设置自动装配
//            builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
//            String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
//            if (initMethod.length() > 0) {
//                builder.setInitMethodName(initMethod);
//            }
//
//        }

        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // ⬇️销毁容器
        context.close();

        /*
            学到了什么
                a. @ComponentScan, @Bean, @Mapper 等注解的解析属于核心容器(即 BeanFactory)的扩展功能
                b. 这些扩展功能由不同的 BeanFactory 后处理器来完成, 其实主要就是补充了一些 bean 定义
         */
    }
}
